package com.fishery.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Date;

/**
 * <p>
 * token工具
 * </p>
 *
 * @author hy
 * @since 2021-01-18
 */
@Component
public class TokenManager {

    //token签名
    @Value("${user.jwt.tokenSignKey}")
    private String tokenSignKey;

    // 过期时间，1小时
    @Value("${user.jwt.ttl}")
    private long ttl;

    //创建新token
    //1。调用Jwts的builder方法，设置该JWT所面向的用户，是否使用是可选的
    /**
     * 一个JWT实际上就是一个字符串，它由三部分组成，头部(Header)、载荷(Payload)与签名(Signature)
     *  id 当前用户ID
     *  issuer 该JWT的签发者，是否使用是可选的
     *  subject 该JWT所面向的用户，是否使用是可选的
     *  ttlMillis 什么时候过期，这里是一个Unix时间戳，是否使用是可选的
     *  audience 接收该JWT的一方，是否使用是可选的
     *  Expiration setExpiration设置过期时间
     */
    public String createToken(String id, String subject, Integer baseIndetity) {
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        JwtBuilder builder = Jwts.builder()
                // JWT的唯一标识，回避重放攻击
                .setId(id)
                // 代表JWT的主体，即它的所有人
                .setSubject(subject)
                // 签发时间
                .setIssuedAt(now)
                // 加密算法、密钥
                .signWith(SignatureAlgorithm.HS256, tokenSignKey)
                .claim("baseIndetity", baseIndetity);
                // 载荷
        if (ttl > 0) {
            // 设置过期时间
            builder.setExpiration(new Date(nowMillis + ttl));
        }
        return builder.compact();
    }

    public String createToken(String id, String username, Integer baseIndetity, String baseId, Collection<GrantedAuthority> authorities) {
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        JwtBuilder builder = Jwts.builder()
                // JWT的唯一标识，回避重放攻击
                .setId(id)
                // 代表JWT的主体，即它的所有人
                .setSubject(username)
                // 签发时间
                .setIssuedAt(now)
                // 加密算法、密钥
                .signWith(SignatureAlgorithm.HS256, tokenSignKey)
                // 载荷
                .claim("roles", baseIndetity)
                .claim("baseId", baseId)
                .claim("authority", authorities);
        if (ttl > 0) {
            // 设置过期时间
            builder.setExpiration(new Date(nowMillis + ttl));
        }
        return builder.compact();
    }

    /**
     * 解析jwt获得body
     * @param token
     * @return
     */
    public Claims parseJWT(String token){
        return  Jwts.parser()
                .setSigningKey(tokenSignKey)
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 解析jwt得到id
     * @param token
     * @return
     */
    public String getIdFromToken(String token) {
        String user = Jwts.parser()
                .setSigningKey(tokenSignKey)
                .parseClaimsJws(token)
                .getBody()
                .getId();
        return user;
    }

    public String getUserFromToken(String token) {
        Claims claims = parseJWT(token);
        String userName = claims.getId();
        return userName;
    }

    /**
     * 更新JWT
     * @param token
     * @return
     */
    public String updateJWT(String token){
        Claims claims = parseJWT(token);
        return claims.get("baseIndetity").toString().equals(0)
                ?
                createToken(claims.getId(),
                        claims.getSubject(),
                        Integer.valueOf(claims.get("baseIndetity").toString()))
                :
                createToken(claims.getId(),
                        claims.getSubject(),
                        Integer.valueOf(claims.get("baseIndetity").toString()),
                        claims.get("baseId").toString(),
                        (Collection<GrantedAuthority>) claims.get("authority")
                );
    }

    /**
     * 移除jwt
     * @param token
     */
    public void removeToken(String token) {

    }
}
